package analiseSintatica.Regras.Declaracoes;

import java.util.LinkedList;

import analiseSintatica.AnalisadorSintatico;
import analiseSintatica.ErroSintaticoException;
import analiseSintatica.Regras.Regra;
//import analiseSintatica.estruturadados.NoArvore;
import AnaliseLexicaFinal.EstruturaDeDados.LinkToken;
import analiseSemantica.ErroSemantico;
import analiseSemantica.Tipos.TipoSemantico;
import analiseSemantica.Tipos.TiposSemanticos;
import analiseSemantica.estruturadedados.Identificador;
import analiseSemantica.estruturadedados.Token;
import analiseSemantica.estruturadedados.Typedef;
//import analiseSintatica.Regras.DeclaracoesIniciais.RegraDeclaracao;
import analiseSintatica.Regras.Tipos.RegraTipoPrimitivo;

/**
 *
 * @author Edney
 */
public class RegraDeclaracao extends Regra {

    protected static Regra instancia;

    protected String estrutura = "(<tipo_primitivo> | identificador) ['*'] identificador <array> {',' ['*'] identificador <array> } ';'";

    /**
     * Construtor privado necessario ao singleton
     */
    private RegraDeclaracao() {
    }

    /**
     * Retorna a unica instancia dessa classe.
     * @return
     */
    public static RegraDeclaracao getInstance() {
        if (instancia == null) {
            instancia = new RegraDeclaracao();
        }
        return (RegraDeclaracao) instancia;
    }

    @Override
    public TiposSemanticos analisar(LinkedList<LinkToken> listaTokens) throws ErroSintaticoException {

    	boolean primeira = true;
    	boolean erros = false;
    	
    	String tipo = null;
    	TiposSemanticos identificadores = new TiposSemanticos();
    	
    	if (listaContem(RegraTipoPrimitivo.getInstance().getPrimeiro(), listaTokens.getFirst())) {
    		TipoSemantico temp = RegraTipoPrimitivo.getInstance().analisar(listaTokens).removeTipos();
    		tipo = (String)temp.getTipo();
	 	} else if (listaTokens.getFirst().getToken().equals("identificador")) {
	 		Token token = AnalisadorSintatico.escopoatual.find(listaTokens.getFirst().getLexema());
        	if (token == null || !(token instanceof Typedef)) {
        		erros = true;
        		AnalisadorSintatico.errosemanticos.add(new ErroSemantico("Esse nao foi definido ", listaTokens.getFirst().getLinha()));
            } else {
                tipo = (String)listaTokens.getFirst().getLexema();
            }
        	listaTokens.removeFirst();
	 	}
    	
    	int linha;
    	while(listaTokens.getFirst().getLexema().equals(",") || primeira){
    		if (!primeira) {
                reconheceLexema(listaTokens, "delimitador", ",", estrutura);
            }
    		primeira = false;
    		
    		Identificador id = new Identificador(null);
    		id.setConstante(false);
    		id.setTipo(tipo);
            
            if (listaTokens.getFirst().getLexema().equals("*")) {
               	id.setPonteiro(true);
           }else{
               	id.setPonteiro(false);
           	}
            
            id.setLexema(listaTokens.getFirst().getLexema());
            linha = listaTokens.getFirst().getLinha();
            reconheceToken(listaTokens, "identificador", estrutura);
            
            int dim = Integer.parseInt((String)RegraArray.getInstance().analisar(listaTokens).removeTipos().getTipo());
            id.setDimensoes(dim);
            
            identificadores.addTipos(new TipoSemantico(id, linha));           	
        }
    	
    	reconheceLexema(listaTokens, "delimitador", ";", estrutura);
    	
    	if(erros)
    		return null;
    	else{
    		if(AnalisadorSintatico.escopoatual == null){
    			return identificadores;
    		}else{
	    		while(identificadores.size() != 0){
	    			TipoSemantico id = identificadores.removeTipos();
	    			Identificador atual = (Identificador)id.getTipo();
	    			
	    			if(AnalisadorSintatico.escopoatual.find(atual.getLexema()) == null){
	    				AnalisadorSintatico.escopoatual.put(atual.getLexema(), atual);
	    			}else{
	    				AnalisadorSintatico.errosemanticos.add(new ErroSemantico("Identificador "+atual.getLexema()+" ja existe", id.getLinha()));
	    			}
	    		}
	    		return null;
    		}
    	}
    }

    @Override
    protected void setPrimeiro() {
        this.primeiro = RegraTipoPrimitivo.getInstance().getPrimeiro();
        this.primeiro = getUniao(primeiro, "identificador");
    }
}
